package client

import (
	"fmt"
	"log"
	. "npxy-go/pkg/proxy/message"
	"npxy-go/pkg/tcp"
)

type bridgeHandler struct {
	tcp.BaseHandler
	conf          *Config
	localSessions *SessionChannelManager
	bridgeSession *tcp.Session
}

func (b *bridgeHandler) OnMessage(_ *tcp.SessionContext, buf *tcp.Buffer) {
	switch m := Decode(buf).(type) {
	case *ConnectionMessage:
		b.connectionLocal(m.Id, m.LocalPort)
	case *DisconnectionMessage:
		b.localSessions.ReleaseById(m.Id)
	case *ForwardMessage:
		b.forwardLocal(buf, m.Id)
	case *ConfigMessage:
		if m.Ok() {
			log.Printf("Proxy built:\t[Local]127.0.0.1:%d\t<->\t%s:%d[Proxy]", m.LocalPort, b.conf.BridgeHost(), m.PortalPort)
		}
	}
}

func (b *bridgeHandler) OnConnected(ctx *tcp.SessionContext) {
	b.bridgeSession = ctx.Session

	log.Println("Bridge connected", ctx.String())

	//build proxy
	buf := tcp.NewBuffer()
	log.Println("Binding: ",b.conf.Bindings)
	for _, p := range b.conf.Bindings {
		cm := ConfigMessage{PortalPort: p.PortalPort,LocalPort: p.LocalPort}
		cm.Encode(buf)
		ctx.Send(buf)
		buf.Reset()
	}
}

func (b *bridgeHandler) OnDisconnected(ctx *tcp.SessionContext) {
	ctx.Session.Close()
	b.bridgeSession = nil
	log.Println("Bridge disconnected", ctx.String())
}

func (b *bridgeHandler) connectionLocal(id int32, lp uint16) {
	ch := b.localSessions.CreateSessionChan(id)

	local := tcp.NewClient(func(pipe tcp.Pipeline) {
		pipe.AddHandlerChain(newLocalHandler(b.localSessions, id, b.bridgeSession))
	})
	local.ReadBufferSize = tcp.DefaultReadBufferSize
	local.ReadHeadSize = TotalHeadSize

	go func() {
		defer close(ch)
		_ = local.Connect(fmt.Sprintf(":%d", lp))
		local = nil
	}()
}

func (b *bridgeHandler) forwardLocal(buf *tcp.Buffer, id int32) {
	if localSes := b.localSessions.GetSession(id); localSes != nil {
		localSes.Send(buf)
		return
	}
	log.Println("Can not forward to local")
}
